using System;
using System.Drawing;
using System.Windows.Forms;

using Pegasus.ServiceModel;
using Pegasus.Windows.Forms;

namespace Pegasus.Sample.PeerToPeerChat
{
	/// <summary>
	/// The sample appliation Chat demonstrates the use of the Pegasus.ServiceModel.PeerNetworkManager class that 
	/// wrappers and enhances the .NET 3.0 (WCF) NetPeerBinding class to create a peer to peer network of nodes
	/// and can send both public broadcast messages (messages to all nodes) and private messages (message to a
	/// specific node)
	/// </summary>
	public partial class FormChat : Form
	{
		// Local Instance Values
		private PeerNetworkManager m_peerManager = null;

		/// <summary>
		/// Initializes a new instance of the <see cref="FormChat"/> class.
		/// </summary>
		public FormChat()
		{
			InitializeComponent();

			// Set the text for the error dialog boxes
			MsgBox.ErrorCaption = "Peer-to-Peer Chat Error";
			MsgBox.NonErrorCaption = "Peer-to-Peer Chat";

			SetControlStates();
		}

		/// <summary>
		/// Handles the Click event of the ButtonConnect control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void ButtonConnect_Click( object sender, EventArgs args )
		{
			try
			{
				UseWaitCursor = true;
				Refresh();

				if( m_peerManager == null )
				{
					// Enter the chat room.

					// Make sure that the user has entered a valid nickname
					if( string.IsNullOrEmpty( TextYourNickname.Text ) )
					{
						MsgBox.ErrorBox( "You must enter a nickname before you can enter the chat room." );
						return;
					}

					m_peerManager = new PeerNetworkManager();
					m_peerManager.MeshName = "PeerToPeerChatRoom";
					m_peerManager.NodeName = TextYourNickname.Text;
					m_peerManager.IgnoreMessagesFromSelf = false;

					m_peerManager.HartbeatInterval = 100;
					m_peerManager.PingInteralval = 500;

					// Setup then event handlers
					m_peerManager.OnNodeEnter += new EventHandler<EventArgsNodeInfo>( PeerManager_OnNodeEnter );
					m_peerManager.OnNodeExit += new EventHandler<EventArgsNodeInfo>( PeerManager_OnNodeExit );
					m_peerManager.OnBroadcastMessageReceived += new EventHandler<EventArgsMessage>( PeerManager_OnBroadcastMessageReceived );
					m_peerManager.OnPrivateMessageReceived += new EventHandler<EventArgsMessage>( PeerManager_OnPrivateMessageReceived );

					SpecialTag tag = new SpecialTag();
					tag.StringOne = "This is a string one.";
					tag.StringTwo = "This is a string two.";
					m_peerManager.NodeTag = tag;

					m_peerManager.Connect();
				}
				else
				{
					// Leave the chat room.
					m_peerManager.Disconnet();
					m_peerManager = null;
				}

				SetControlStates();
			}
			finally
			{
				UseWaitCursor = false;
			}
		}

		/// <summary>
		/// Handles the Click event of the ButtonSendPublic control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void ButtonSendPublic_Click( object sender, EventArgs args )
		{
			if( !string.IsNullOrEmpty( TextYourMessage.Text ) )
			{
				m_peerManager.SendBroadcastMessage( TextYourMessage.Text );
				TextYourMessage.Text = string.Empty;
				TextYourNickname.Focus();
			}
		}

		/// <summary>
		/// Handles the Click event of the ButtonSendPrivate control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void ButtonSendPrivate_Click( object sender, EventArgs args )
		{
			// The user must have another node selected in the people list
			// and it can't be ourself.
			NodeInfo selectedNode = (NodeInfo) ListPeople.SelectedItem;
			if( selectedNode == null || selectedNode.Name == TextYourNickname.Text )
			{
				MsgBox.ErrorBox( "You must select a person to send the message to." );
				return;
			}

			if( !string.IsNullOrEmpty( TextYourMessage.Text ) )
			{
				m_peerManager.SendPrivateMessage( selectedNode.Name, TextYourMessage.Text );
				TextYourMessage.Text = string.Empty;
				TextYourNickname.Focus();
			}
		}

		/// <summary>
		/// Handles the OnNodeEnter event of the PeerManager control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void PeerManager_OnNodeEnter( object sender, EventArgsNodeInfo args )
		{
			// PeerManager events can come in on background threads to we need to 
			// check to see if this event can talk directly to the UI or if we
			// need to call this method again no the proper thread.
			if( InvokeRequired )
			{
				Invoke( new EventHandler<EventArgsNodeInfo>( PeerManager_OnNodeEnter ), sender, args );
			}
			else
			{
				TextChat.AppendText( string.Format( "** {0} Entered Chat Room\n", args.Node.Name ) );
				SetControlStates();
			}
		}

		/// <summary>
		/// Handles the OnNodeExit event of the PeerManager control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void PeerManager_OnNodeExit( object sender, EventArgsNodeInfo args )
		{
			// PeerManager events can come in on background threads to we need to 
			// check to see if this event can talk directly to the UI or if we
			// need to call this method again no the proper thread.
			if( InvokeRequired )
			{
				Invoke( new EventHandler<EventArgsNodeInfo>( PeerManager_OnNodeExit ), sender, args );
			}
			else
			{
				TextChat.AppendText( string.Format( "** {0} Left Chat Room\n", args.Node.Name ) );
				SetControlStates();
			}
		}

		/// <summary>
		/// Handles the OnBroadcastMessageReceived event of the PeerManager control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="Pegasus.ServiceModel.EventArgsMessage"/> instance containing the event data.</param>
		private void PeerManager_OnBroadcastMessageReceived( object sender, EventArgsMessage args )
		{
			// PeerManager events can come in on background threads to we need to 
			// check to see if this event can talk directly to the UI or if we
			// need to call this method again no the proper thread.
			if( InvokeRequired )
			{
				Invoke( new EventHandler<EventArgsMessage>( PeerManager_OnBroadcastMessageReceived ), sender, args );
			}
			else
			{
				TextChat.AppendText( string.Format( "[{0}] {1}\n", args.Name, args.Message ) );
			}
		}

		/// <summary>
		/// Handles the OnBroadcastMessageReceived event of the PeerManager control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="Pegasus.ServiceModel.EventArgsMessage"/> instance containing the event data.</param>
		private void PeerManager_OnPrivateMessageReceived( object sender, EventArgsMessage args )
		{
			// PeerManager events can come in on background threads to we need to 
			// check to see if this event can talk directly to the UI or if we
			// need to call this method again no the proper thread.
			if( InvokeRequired )
			{
				Invoke( new EventHandler<EventArgsMessage>( PeerManager_OnPrivateMessageReceived ), sender, args );
			}
			else
			{
				TextChat.AppendText( string.Format( "Private [{0}] {1}\n", args.Name, args.Message ) );
			}
		}

		/// <summary>
		/// Sets the states of the control on the main form.
		/// </summary>
		private void SetControlStates()
		{
			if( m_peerManager == null )
			{
				LabelChatText.Enabled = false;
				TextChat.Enabled = false;
				LabelYourMessage.Enabled = false;
				TextYourMessage.Enabled = false;

				LabelYourNickname.Enabled = true;
				TextYourNickname.Enabled = true;
				ButtonConnect.Text = "Enter Chat Room";

				LabelPeople.Enabled = false;
				ListPeople.Enabled = false;
				ListPeople.Items.Clear();

				ButtonSendPublic.Enabled = false;
				ButtonSendPrivate.Enabled = false;
			}
			else
			{
				LabelChatText.Enabled = true;
				TextChat.Enabled = true;
				LabelYourMessage.Enabled = true;

				LabelYourNickname.Enabled = false;
				TextYourNickname.Enabled = false;
				ButtonConnect.Text = "Leave Chat Room";

				LabelPeople.Enabled = true;
				ListPeople.Enabled = true;

				ListPeople.Items.Clear();

				// Get the nodes and if we are the only one in the mesh
				// then wait for others to enter the chat room.
				bool waitingForOthers = true;
				if( m_peerManager != null && m_peerManager.IsConnected )
				{
					NodeInfo[] nodes = m_peerManager.GetMemberNodes();
					if( nodes.Length > 1 )
					{
						waitingForOthers = false;

						// Add the people that are on line to the list
						ListPeople.Items.AddRange( m_peerManager.GetMemberNodes() );

						TextYourMessage.Enabled = true;

						ButtonSendPublic.Enabled = true;
						ButtonSendPrivate.Enabled = true;
					}
				}

				if( waitingForOthers )
				{
					// Wait for other to join the chat.
					ListPeople.Items.Add( "(Waiting for others to join)" );

					TextYourMessage.Enabled = false;

					ButtonSendPublic.Enabled = false;
					ButtonSendPrivate.Enabled = false;
				}
			}
		}
	}
}